package personnal.jonat;
import static personnal.jonat.PropertiesUtils.*;
import static personnal.jonat.ExcelUtils.getCellValueAsDouble;
import static personnal.jonat.ExcelUtils.getCellValueAsString;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

public class StudentExtractor {

    private static final Logger logger = Logger.getLogger(StudentExtractor.class);

    protected static final int GRADES_SHEET_INDEX = 0;

//    protected static final short CLASSNAME_ROW_INDEX = 0;
//    protected static final short CLASSNAME_COLUMN_INDEX = 1;
    
    protected static final int STUDENT_ROW_START_INDEX = 4;
    protected static final int STUDENTNAME_COLUMN_INDEX = 1;
    protected static final int AVERAGE_GRADE_COLUMN_INDEX = 3;
    protected static final int SKILL_COLUMN_START_INDEX = 7;

    private int sheetIndex = GRADES_SHEET_INDEX;

//    private short classNameRowIndex = CLASSNAME_ROW_INDEX;
//    private short classNameColumnIndex = CLASSNAME_COLUMN_INDEX;
    
    private int studentRowStartIndex = STUDENT_ROW_START_INDEX;
    private int studentNameColumnIndex = STUDENTNAME_COLUMN_INDEX;
    private int averageGradeColumnIndex = AVERAGE_GRADE_COLUMN_INDEX;
    private int skillColumnStartIndex = SKILL_COLUMN_START_INDEX;

    private int skillColumnEndIndex;
    private int studentRowEndIndex;
    private int classGradeRowIndex;

    public StudentExtractor(int studentCount, int skillCount) {
		super();
        this.skillColumnEndIndex = skillColumnStartIndex + skillCount;
        this.studentRowEndIndex = studentRowStartIndex + studentCount;
        this.classGradeRowIndex = skillColumnStartIndex + studentCount;
	}

    public StudentExtractor(Properties properties) {
		super();
		int skillCount = defaultInt(properties, "source.skill.count", 1);
		int studentCount = defaultInt(properties, "source.student.count", 1);

		this.sheetIndex = defaultInt(properties, "source.sheet.index", GRADES_SHEET_INDEX);
		this.studentRowStartIndex = defaultInt(properties, "source.student.row.startIndex", STUDENT_ROW_START_INDEX);
		this.studentNameColumnIndex = defaultInt(properties, "source.studentName.column.index", STUDENTNAME_COLUMN_INDEX);
		this.averageGradeColumnIndex =  defaultInt(properties, "source.averageGrade.column.index", AVERAGE_GRADE_COLUMN_INDEX);
		this.skillColumnStartIndex = defaultInt(properties, "source.skill.column.startIndex", SKILL_COLUMN_START_INDEX);
		this.skillColumnEndIndex = skillColumnStartIndex + skillCount;
		this.studentRowEndIndex = studentRowStartIndex + studentCount;
		this.classGradeRowIndex = defaultInt(properties, "source.classAverageGrade.row.index", skillColumnStartIndex + studentCount);
	}

	public OutCome extractStudents(File inputFile) throws IOException {
        InputStream inputStream = new FileInputStream(inputFile);
        try (HSSFWorkbook wb = new HSSFWorkbook(inputStream)) {
            HSSFSheet gradesSheet = wb.getSheetAt(sheetIndex);
//            logger.info("Extraction du titre");
//            HSSFCell titleCell = getOrCreateCell(gradesSheet, CLASSNAME_ROW_INDEX, CLASSNAME_COLUMN_INDEX);
//            String title = getCellValueAsString(titleCell);
            String title = null;
            logger.info("Extraction des moyennes de la classe");
            HSSFRow classGradeRow = gradesSheet.getRow(classGradeRowIndex);
            List<Double> classGrades = extractRowGrades(classGradeRow, skillColumnEndIndex);
            logger.debug("Nombre de notes extraites: " + classGrades.size());
            logger.info("Extraction des notes de chaque élève");
            List<Student> students = extractStudentGrades(gradesSheet, classGrades, studentRowEndIndex,
                    skillColumnEndIndex);
            logger.debug("Nombre d'élèves extraits: " + students.size());
            return new OutCome(title, students);
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }

    protected List<Student> extractStudentGrades(HSSFSheet gradesSheet, List<Double> classGrades,
            int studentRowEndIndex, int skillColumnEndIndex) {
        List<Student> students = new LinkedList<Student>();
        for (int rowIndex = studentRowStartIndex; rowIndex < studentRowEndIndex; rowIndex++) {
            Student student = extractStudent(gradesSheet, classGrades, rowIndex, skillColumnEndIndex);
            students.add(student);
        }
        return students;
    }

    protected Student extractStudent(HSSFSheet gradesSheet, List<Double> classGrades, int rowIndex,
            int skillColumnEndIndex) {
        HSSFRow studentRow = gradesSheet.getRow(rowIndex);
        Student student = new Student();
        student.setClassGrades(classGrades);
        student.setName(getCellValueAsString(studentRow.getCell(studentNameColumnIndex)));
        student.setAverageGrade(getCellValueAsDouble(studentRow.getCell(averageGradeColumnIndex)));
        logger.debug("Extraction des notes de " + student.getName());
        List<Double> grades = extractRowGrades(studentRow, skillColumnEndIndex);
        student.setGrades(grades);
        return student;
    }

    /**
     * Extrait les notes moyennes de la classe
     */
    protected List<Double> extractRowGrades(HSSFRow gradeRow, int skillColumnEndIndex) {
        List<Double> grades = new ArrayList<Double>(skillColumnEndIndex - skillColumnStartIndex);
        for (int columnIndex = skillColumnStartIndex; columnIndex < skillColumnEndIndex; columnIndex++) {
            HSSFCell gradeCell = gradeRow.getCell(columnIndex);
            Double grade = getCellValueAsDouble(gradeCell);
            grades.add(grade);
            logger.trace("Note: " + grade);
        }
        return grades;
    }
}
